import sys
import datetime
import time
import math
import RPi.GPIO as GPIO

#"""max31865芯片驱动类"""
class max31865(object):

    # 初始化树莓派SPI引脚配置
    def __init__(self, csPin, misoPin, mosiPin, clkPin, drdyPin):
        # 片选
        self.csPin = csPin    
        # 数据输入
        self.misoPin = misoPin  
        # 数据输出
        self.mosiPin = mosiPin  
        # 时钟
        self.clkPin = clkPin    
        # 数据就绪
        self.drdyPin = drdyPin  
        self.setupGPIO()

    # GPIO设置
    def setupGPIO(self):
        # 取消复用警告
        GPIO.setwarnings(False)  
        # 设置GPIO为BCM模式
        GPIO.setmode(GPIO.BCM)  
        GPIO.setup(self.csPin, GPIO.OUT)
        GPIO.setup(self.misoPin, GPIO.IN)
        GPIO.setup(self.mosiPin, GPIO.OUT)
        GPIO.setup(self.clkPin, GPIO.OUT)
        GPIO.setup(self.drdyPin, GPIO.IN)

        GPIO.output(self.csPin, GPIO.HIGH)
        GPIO.output(self.clkPin, GPIO.LOW)
        GPIO.output(self.mosiPin, GPIO.LOW)

    # 写入寄存器数据
    def writeRegister(self, addressByte, dataByte):
        GPIO.output(self.csPin, GPIO.LOW)
        # 写入地址位
        self.sendByte(addressByte)
        # 写入数据位
        self.sendByte(dataByte)
        GPIO.output(self.csPin, GPIO.HIGH)

    # 读取寄存器信息
    def readRegisters(self, regNumStart, numRegisters):
        # 当drdy为低电平时读取数据
        while True:
            if(not(GPIO.input(self.drdyPin))):
                break
            time.sleep(0.1)

        out = []
        GPIO.output(self.csPin, GPIO.LOW)
        self.sendByte(regNumStart)
        for byte in range(numRegisters):
            data = self.recvByte()
            out.append(data)
        GPIO.output(self.csPin, GPIO.HIGH)
        return out

    # 写入数据
    def sendByte(self, byte):
        for bit in range(8):
            GPIO.output(self.clkPin, GPIO.HIGH)
            if (byte & 0x80):
                GPIO.output(self.mosiPin, GPIO.HIGH)
            else:
                GPIO.output(self.mosiPin, GPIO.LOW)
            byte <<= 1
            GPIO.output(self.clkPin, GPIO.LOW)

    # 接收数据
    def recvByte(self):
        # 初始数据
        byte = 0x00
        for bit in range(8):
            GPIO.output(self.clkPin, GPIO.HIGH)
            # 数据移位
            byte <<= 1
            if GPIO.input(self.misoPin):
                # 数据填充
                byte |= 0x01
            GPIO.output(self.clkPin, GPIO.LOW)
        return byte

    # 温度换算
    def calcPT100Temp(self, RTD_ADC_Code):
        # print("ADC Code: %d" % RTD_ADC_Code)
        # PT100 电阻
        R_REF = 400.0  # 基准电阻
        Res_RTD = (RTD_ADC_Code * R_REF) / 32767.0
        # print("PT100 电阻: %f" % Res_RTD)
        # 线性温度换算
        temp_C_line = (RTD_ADC_Code / 32) - 256.0
        # print("线性温度: %f " % temp_C_line)
        # Callendar-Van Dusen方程温度换算
        # 方程系数
        a = 3.90830 * pow(10, -3)
        b = -5.77500 * pow(10, -7)
        temp_C = -a + math.sqrt((a * a) - (4 * b) * (1 - (Res_RTD / 100.0)))
        temp_C = temp_C / (2 * b)
        # print("Callendar-Van Dusen方程温度 (degC > 0): %f " % temp_C)
        return temp_C

    # 转换预警阈值温度数据
    def calcTempThresholdByte(self, temp):
        # 将温度转换位ADC Code 值
        RTD_ADC_Code = (temp + 256.0) * 32
        byte = int(RTD_ADC_Code) << 1
        # 温度值高位数据
        msbAddressByte = (byte & 0xFF00) >> 8
        # 温度值低位数据
        lsbAddressByte = byte & 0xFF
        return [msbAddressByte, lsbAddressByte]

    # 设置温度超高预警阈值
    def setHighTempThreshold(self, temp):
        thresholdByte = self.calcTempThresholdByte(temp)
        self.writeRegister(0x83, thresholdByte[0])
        self.writeRegister(0x84, thresholdByte[1])

    # 设置温度超低预警阈值
    def setLowTempThreshold(self, temp):
        thresholdByte = self.calcTempThresholdByte(temp)
        self.writeRegister(0x85, thresholdByte[0])
        self.writeRegister(0x86, thresholdByte[1])

    # 获取温度
    def readTemp(self):
        # 配置寄存器
        # ---------------
        # bit 7: Vbias -> 1 (ON)
        # bit 6: Conversion Mode -> 0 (MANUAL)
        # bit5: 1-shot ->1 (ON)
        # bit4: 3-wire select -> 1 (3 wire config)
        # bits 3-2: fault detection cycle -> 0 (none)
        # bit 1: fault status clear -> 1 (clear any fault)
        # bit 0: 50/60 Hz filter select -> 0 (60Hz)
        # 0b11010011= 0xD3
        #
        # 写入配置信息
        self.writeRegister(0x80, 0xD3)
        time.sleep(0.02)
        # 读取寄存器所有值
        out = self.readRegisters(0x00, 8)
        # out[1]:RTD MSBs
        # out[2]:RTD LSBs
        [rtd_msb, rtd_lsb] = [out[1], out[2]]
        # 计算 ADC Code 值
        rtd_ADC_Code = ((rtd_msb << 8) | rtd_lsb) >> 1
        # 将ADC Code值 转换为温度值
        temp_C = self.calcPT100Temp(rtd_ADC_Code)
        [hft_msb, hft_lsb] = [out[3], out[4]]
        hft = ((hft_msb << 8) | hft_lsb) >> 1
        #print("超高预警阈值: %d" % self.calcPT100Temp(hft))

        [lft_msb, lft_lsb] = [out[5], out[6]]
        lft = ((lft_msb << 8) | lft_lsb) >> 1
        #print("超低预警阈值: %d" % self.calcPT100Temp(lft))
        # 故障码
        faultCode = 0
        status = out[7]
        if ((status & 0x80) == 0x80):
            faultCode = 208
        if ((status & 0x40) == 0x40):
            faultCode = 207
        if ((status & 0x04) == 0x04):
            faultCode = 203

        #print(self.getFaultDesc(faultCode))
        return [temp_C, faultCode]

    def getFaultDesc(self, faultCode):
        desc = ""
        if(faultCode == 203):
            desc = "过压或欠压！"
        elif(faultCode == 207):
            desc = "温度超低预警！"
        elif(faultCode == 208):
            desc = "温度超高预警！"
        return desc


if __name__ == "__main__":
    import max31865
    max = max31865.max31865(5, 9, 10, 11, 6)
    # max.setHighTempThreshold(int(100))
    # max.setLowTempThreshold(int(0))
    # f = open('/home/pi/Downloads/11s111/New/test.txt', 'r+')
    while True:
        tempareture = max.readTemp()[0]
        #print('{:%Y-%m-%d %H:%M:%S} temp {:5.2f}'.format(datetime.datetime.now(), tempareture))
        # f.writelines("%S %S" % (tempareture, tempareture))
        # f.flush()
        time.sleep(1)
    # f.close()
    GPIO.cleanup()
